﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WMM.Tapioca.Taxonomy;
using System.Collections;

namespace WMM.Tapioca.XbrlDimension
{
    /// <summary>
    /// The relationship arc role http://xbrl.org/int/dim/arcrole/hypercube-dimension. 
    /// </summary>
    public class HypercubeDimension : DRSRelationship
    {
        private Hypercube hypercube;

        /// <returns> hypercube of this relationship. </returns>
        public Hypercube Hypercube
        {
            get { return hypercube; }
            set { hypercube = value; }
        }

        private Dimension dimension; // Dimension objects        

        /// <returns> Set with Dimension objects representing all the
        ///         set of Dimensions this hypercube consists of. </returns>
        public virtual Dimension Dimension
        {
            get { return dimension; }
            set { dimension = value; }
        }

        private string arcRole;

        /// <returns> A arc role. </returns>
        public string ArcRole
        {
            get { return arcRole; }
            set { arcRole = value; }
        }

        private string closed;

        /// <returns> If this hypercube can be extended. </returns>
        /// the hypercube is closed with respect to the element in that base set.
        public string Closed
        {
            get { return closed; }
            set { closed = value; }
        }

        private bool summable;

        /// <returns> summable of this hypercube. </returns>
        public bool Summable
        {
            get { return summable; }
            set { summable = value; }
        }

        /// <summary>
        /// HypercubeDimension constructor.
        /// </summary>
        public HypercubeDimension()
        {
            //this.hypercube = hypercube;
            //dimensionSet = new List<Dimension>();
        }

        /// <summary>
        /// Adds a dimension to the cube.
        /// </summary>
        /// <param name="dimension">
        ///            The dimension which shall be added. </param>
        public virtual void addDimension(Dimension dimension)
        {
            //dimensionSet.Add(dimension);
        }

        /// <summary>
        /// Gets the set of domain members to a dimension contained in the cube.
        /// </summary>
        /// <param name="dimension">
        ///            The dimension for which the domain shall be returned. </param>
        /// <returns> A list with xbrlcore.xlink.ExtendedLinkElement objects
        ///         representing the domain of the dimension. </returns>
        public virtual List<KeyValuePair<string, Concept>> getDimensionDomain(Concept dimension)
        {
            //IEnumerator dimensionIterator = dimensionSet.GetEnumerator();
            //while (dimensionIterator.MoveNext())
            //{
            //    Dimension currDimension = (Dimension)dimensionIterator.Current;
            //    if (currDimension.Concept.Equals(dimension))
            //    {
            //        return currDimension.DomainMemberSet;
            //    }
            //}
            return null;
        }


        /// <summary>
        /// Specifies whether a certain dimension is part of that cube.
        /// </summary>
        /// <param name="dimension">
        ///            The Concept object representing the according dimension. </param>
        /// <returns> True if the dimension is part of that cube, otherwise false. </returns>
        public virtual bool containsDimension(Concept dimension)
        {
            //IEnumerator dimensionIterator = dimensionSet.GetEnumerator();
            //while (dimensionIterator.MoveNext())
            //{
            //    Dimension currDimension = (Dimension)dimensionIterator.Current;
            //    if (currDimension.Concept.Equals(dimension))
            //    {
            //        return true;
            //    }
            //}
            return false;
        }

        /// <summary>
        /// Specifies whether a certain dimension with a certain domain member is
        /// part of that cube. This method does not take into account whether the
        /// given domain member has an xbrldt:usable attribute or not (use
        /// containsUsableDimensionDomain instead).
        /// </summary>
        /// <param name="dimension">
        ///            The Concept object representing the according dimension. </param>
        /// <param name="domainMember">
        ///            The Concept object representing the according domain. </param>
        /// <returns> True if the dimension/domain combination is part of that cube,
        ///         otherwise false. If the dimension is a typed dimension, the
        ///         method always returns true. </returns>
        public virtual bool containsDimensionDomain(Concept dimension, Concept domainMember)
        {
            //IEnumerator dimensionIterator = dimensionSet.GetEnumerator();
            //while (dimensionIterator.MoveNext())
            //{
            //    Dimension currDimension = (Dimension)dimensionIterator.Current;
            //    if (currDimension.Concept.Equals(dimension))
            //    {
            //        /*
            //         * TODO: a typed dimension always returns "true", so ALL
            //         * elements can be domain member of a typed dimension. Later it
            //         * must be checked whether the element is compliant with the
            //         * according schema element.
            //         */
            //        return (currDimension.Typed ? true : currDimension.containsDomainMember(domainMember, false));
            //    }
            //}
            return false;
        }

        /// <summary>
        /// Specifies whether a certain dimension with a certain domain member is
        /// part of that cube. This method takes into account whether the given
        /// domain member has an xbrldt:usable attribute or not. If the usable
        /// attribute is set to false, it returns false.
        /// </summary>
        /// <param name="dimension">
        ///            The Concept object representing the according dimension. </param>
        /// <param name="domainMember">
        ///            The Concept object representing the according domain. </param>
        /// <returns> True if the dimension/domain combination is part of that cube,
        ///         otherwise false. If the dimension is a typed dimension, the
        ///         method always returns true. </returns>
        public virtual bool containsUsableDimensionDomain(Concept dimension, Concept domainMember)
        {
            //IEnumerator dimensionIterator = dimensionSet.GetEnumerator();
            //while (dimensionIterator.MoveNext())
            //{
            //    Dimension currDimension = (Dimension)dimensionIterator.Current;
            //    if (currDimension.Concept.Equals(dimension))
            //    {
            //        /*
            //         * TODO: a typed dimension always returns "true", so ALL
            //         * elements can be domain member of a typed dimension. Later it
            //         * must be checked whether the element is compliant with the
            //         * according schema element.
            //         */
            //        return (currDimension.Typed ? true : currDimension.containsDomainMember(domainMember, true));
            //    }
            //}
            return false;
        }

        /// <summary>
        /// Adds all the dimensions / domain member of a second hypercube to this
        /// hypercube. This is done in the following way: If the second hypercube has
        /// a dimension which is not contained in this cube, the dimension and all
        /// its domain members are added to this cube. If the second hypercube has a
        /// dimension which is already contained in this cube, all domain members of
        /// this dimension of the second cube which are not part of the same
        /// dimension of this cube are added to this cube.
        /// </summary>
        /// <param name="newCube">
        ///            The second cube whose dimension/domain members are added to
        ///            this cube. </param>
        //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
        //ORIGINAL LINE: public void addHypercube(Hypercube newCube) throws CloneNotSupportedException
        public virtual void addHypercube(Hypercube newCube)
        {
            /* go through all the dimensions of newCube */
            //List<Dimension> newDimensionSet = this.DimensionSet;
            //IEnumerator newDimensionSetIterator = newDimensionSet.GetEnumerator();
            //while (newDimensionSetIterator.MoveNext())
            //{
            //    Dimension newCubeDimension = (Dimension)newDimensionSetIterator.Current;
            //    /* if it is contained in this cube, add only the domain members */
            //    if (containsDimension(newCubeDimension.Concept))
            //    {
            //        Dimension thisDimension = GetDimension(newCubeDimension.Concept);
            //        //thisDimension.addDomainMemberSet((Set)((HashSet)newCubeDimension.DomainMemberSet).clone());
            //    }
            //    /*
            //     * if it is not contained in this cube, add it including all the
            //     * domain members
            //     */
            //    else
            //    {
            //        //dimensionSet.Add(newCubeDimension.Clone());
            //    }
            //}
        }

        /// 
        /// <returns> String object describing this hypercube. </returns>
        public override string ToString()
        {
            //string id = (hypercube != null ? hypercube.Concept.Id : "anonymous");
            //string str = "Hypercube " + id + "\n";
            //IEnumerator dimensionIterator = dimensionSet.GetEnumerator();
            //while (dimensionIterator.MoveNext())
            //{
            //    Dimension currDim = (Dimension)dimensionIterator.Current;
            //    str += "\tDimension: " + currDim.Concept.Id + "\n";
            //    List<KeyValuePair<string, Concept>> domainMemberSet = currDim.DomainMemberSet;
            //    IEnumerator domainMemberIterator = domainMemberSet.GetEnumerator();
            //    while (domainMemberIterator.MoveNext())
            //    {
            //        //Concept currCon = ((Locator)domainMemberIterator.Current).Concept;
            //        //str += "\t\tDomain Member: " + currCon.Id + "\n";
            //    }
            //}
            //str += "Hypercube " + id + " finished\n";
            return "";
        }


        ///// <summary>
        ///// Checks whether this hypercube contains specific dimension/domain member
        ///// combinations.
        ///// </summary>
        ///// <param name="mdt">
        /////            Object describing the specific dimension/domain member
        /////            combinations for which this hypercube is checkted. </param>
        ///// <returns> True if and only if this hypercube contains all the
        /////         dimension/domain member combinations described in the given
        /////         MultipleDimensionType object. The hypercube also must not contain
        /////         additinal dimension/domain member combinations than those which
        /////         are contained in the given MultipleDimensinType object. Otherwise
        /////         false is returned. </returns>
        //public virtual bool hasDimensionCombination(MultipleDimensionType mdt)
        //{
        //    IDictionary dimensionDomainMap = mdt.AllDimensionDomainMap;
        //    if (dimensionDomainMap.Count != dimensionSet.size())
        //    {
        //        return false;
        //    }
        //    //JAVA TO C# CONVERTER TODO TASK: There is no .NET Dictionary equivalent to the Java 'entrySet' method:
        //    Set dimensionDomainEntrySet = dimensionDomainMap.entrySet();
        //    IEnumerator dimensionDomainIterator = dimensionDomainEntrySet.GetEnumerator();
        //    while (dimensionDomainIterator.MoveNext())
        //    {
        //        DictionaryEntry currEntry = (DictionaryEntry)dimensionDomainIterator.Current;
        //        Concept currDimConcept = (Concept)currEntry.Key;
        //        Concept currDomConcept = (Concept)currEntry.Value;
        //        if (!containsUsableDimensionDomain(currDimConcept, currDomConcept))
        //        {
        //            return false;
        //        }
        //    }
        //    return true;
        //}

        /// <summary>
        /// Returns a certain dimension from the cube.
        /// </summary>
        /// <param name="dimensionElement">
        ///            Concept object representing the dimension. </param>
        /// <returns> Dimension object matching the given Concept object. </returns>
        public virtual Dimension GetDimension(Concept dimensionElement)
        {
            //IEnumerator dimensionIterator = dimensionSet.GetEnumerator();
            //while (dimensionIterator.MoveNext())
            //{
            //    Dimension currDimension = (Dimension)dimensionIterator.Current;
            //    if (currDimension.Concept.Equals(dimensionElement))
            //    {
            //        return currDimension;
            //    }
            //}
            return null;
        }
    }
}
